using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace Neovolve.Windows.Forms
{
    internal class ControlPositionComparer : IComparer<Control>, IComparer
    {
        #region Declarations

        /// <summary>
        /// Defines the control vertical alignment values.
        /// </summary>
        private enum ControlVerticalAlignment : byte
        {
            None = 1,
            Top = 2,
            Middle = 3,
            Bottom = 4
        }

        #endregion

        #region Methods

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zerox is less than y.Zerox equals y.Greater than zerox is greater than y.
        /// </returns>
        public int Compare(Control x, Control y)
        {
            // Ensure that there are two controls to compare
            if ((x == null)
                || (y == null))
            {
                // There is not a valid comparison
                return 0;
            }

            // Attempt to determine whether the controls are vertically aligned against each other
            ControlVerticalAlignment virticalAlignment = DetermineControlVerticalAlignment(x, y);

            // Compare the positions of the controls
            if (virticalAlignment != ControlVerticalAlignment.None)
            {
                return (x.Left.CompareTo(y.Left));
            }
            else if (x.Top < y.Top)
            {
                return -1;
            }
            else if (x.Top > y.Top)
            {
                return 1;
            }

            return 0;
        }

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero x is less than y. Zero x equals y. Greater than zero x is greater than y.
        /// </returns>
        /// <exception cref="T:System.ArgumentException">Neither x nor y implements the <see cref="T:System.IComparable"></see> interface.-or- x and y are of different types and neither one can handle comparisons with the other. </exception>
        public int Compare(object x, object y)
        {
            // Check if the objects are controls
            if ((x is Control)
                && (y is Control))
            {
                return Compare(x as Control, y as Control);
            }

            return 0;
        }

        /// <summary>
        /// Determines the control vertical alignment.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <returns>The alignment value.</returns>
        private ControlVerticalAlignment DetermineControlVerticalAlignment(Control x, Control y)
        {
            if (x.Top == y.Top)
            {
                return ControlVerticalAlignment.Top;
            }
            else if (x.Bottom == y.Bottom)
            {
                return ControlVerticalAlignment.Bottom;
            }
            else
            {
                // Check if the controls are aligned to their middle
                // This check should also allow for the alignments to be calculated as one pixel out
                int middleX = (x.Top + (x.Height / 2));
                int middleY = (y.Top + (y.Height / 2));

                if ((middleX == middleY)
                    || (Convert.ToInt32(Math.Abs(middleX - middleY)) == 1))
                {
                    return ControlVerticalAlignment.Middle;
                }
                else
                {
                    return ControlVerticalAlignment.None;
                }
            }
        }

        #endregion
    }
}
